package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.CourseBaseDTO;
import com.xuecheng.api.content.model.qo.QueryCourseBaseModel;
import com.xuecheng.api.content.model.vo.CourseAuditVO;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.common.AuditEnum;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.SecurityUtil;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.content.common.constant.ContentErrorCode;
import com.xuecheng.content.convert.CourseBaseConvert;
import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.CourseMarket;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.xuecheng.content.service.CourseMarketService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;

/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseService {

    @Autowired
    private CourseMarketService courseMarketService;


    /*
    * 步骤分析：
    *  1.是否需要开启事务
    *  2.判断关键数据
    *       分页数据
    *       查询条件
    *  3.构建mp分页对象
    *  4.构建查询条件对象LambdaQueryWrapper
    *  5.查询数据
    *  6.获得数据并封装返回结果
    *       封装PageVo数据
    * */
    public PageVO queryCourseBaseList(PageRequestParams params, QueryCourseBaseModel model,Long companyId) {

        //1.是否需要开启事务
        // 查询无需开启事务
        // 2.判断关键数据
        //      分页数据
        //      查询条件

        // 2.1 判断分页数据
        Long pageNo = params.getPageNo();
        Integer pageSize = params.getPageSize();

        if (ObjectUtils.isEmpty(pageNo) || pageNo < 0) {
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }

        if (ObjectUtils.isEmpty(pageSize) || pageSize < 0) {
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }

        // 2.2.构建查询条件对象LambdaQueryWrapper
        // 完成第四部中的构建查询条件
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();

        // 完整版
        // select * from course_base where name = ? and auditStatus = ? and companyId = ?
        // if (StringUtil.isNotBlank(model.getCourseName())) {
        //     queryWrapper.eq(CourseBase::getName,model.getCourseName());
        // }
        //
        // if (StringUtil.isNotBlank(model.getAuditStatus())) {
        //     queryWrapper.eq(CourseBase::getAuditStatus,model.getAuditStatus());
        // }

        // 简版
        queryWrapper.like(StringUtil.isNotBlank(model.getCourseName()),CourseBase::getName,model.getCourseName());
        queryWrapper.eq(StringUtil.isNotBlank(model.getAuditStatus()),CourseBase::getAuditStatus,model.getAuditStatus());
        queryWrapper.eq(!(ObjectUtils.isEmpty(companyId)),CourseBase::getCompanyId,companyId);
        queryWrapper.eq(CourseBase::getStatus, CommonEnum.USING_FLAG.getCode());


        // 3.构建mp分页对象
        Page<CourseBase> page = new Page<>(params.getPageNo(),params.getPageSize());


        // 5.查询数据
        Page<CourseBase> pageResult = this.page(page, queryWrapper);

        // 获得当前页的集合数据
        List<CourseBase> records = pageResult.getRecords();

        // 查询数据的总记录数
        long total = pageResult.getTotal();


        // 将po数据转为dto数据
        List<CourseBaseDTO> dtos = Collections.EMPTY_LIST;


        if (!(CollectionUtils.isEmpty(records))) {
            dtos = CourseBaseConvert.INSTANCE.entitys2dtos(records);
        }



        // 6.获得数据并封装返回结果
        //      封装PageVo数据
        PageVO pageVO = new PageVO(dtos, total, params.getPageNo(), params.getPageSize());


        return pageVO;
    }

    //1.是否需要开启事务
    // 查询无需开启事务
    // 2.判断关键数据
    //      分页数据
    //      查询条件
    @Override
    public PageVO queryCourseList(PageRequestParams params, QueryCourseBaseModel model, Long companyId) {
        //判断分页数据
        Long pageNo = params.getPageNo();
        Integer pageSize = params.getPageSize();
        if (ObjectUtils.isEmpty(pageNo)||pageNo<0){
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }
        if(ObjectUtils.isEmpty(pageSize)||pageSize<0){
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }
        //构建查询条件
        LambdaQueryWrapper<CourseBase> queryWrapper = Wrappers.lambdaQuery(CourseBase.class);
        //select * from coursebase where
        queryWrapper.like(StringUtil.isNotBlank(model.getCourseName()),CourseBase::getName,model.getCourseName());
        queryWrapper.eq(StringUtil.isNotBlank(model.getAuditStatus()),CourseBase::getAuditStatus,model.getAuditStatus());
        queryWrapper.eq(CourseBase::getCompanyId,companyId);
        queryWrapper.eq(CourseBase::getStatus, CommonEnum.USING_FLAG.getCode());

        //构建分页对象
        Page<CourseBase> courseBasePage = new Page<CourseBase>(pageNo,pageSize);
        //查询
        Page<CourseBase> page = this.page(courseBasePage);
        //获得当前页的集合数据
        List<CourseBase> list = page.getRecords();
        //查询总记录数
        long total = page.getTotal();
        //
        List emptyList = Collections.EMPTY_LIST;
        if (!(CollectionUtils.isEmpty(list))) {
            emptyList = CourseBaseConvert.INSTANCE.entitys2dtos(list);
        }
        //      封装PageVo数据
        PageVO pageVO = new PageVO(emptyList, total, params.getPageNo(), params.getPageSize());
        return pageVO;
    }

    /*
    * 业务分析：
    *   1.是否开启事务
    *     新增操作需要开启事务
    *       如果新增操作只会操作一张表而且只会操作一次，那么可以忽略事务
    *   2.判断关键数据
    *       课程基础信息
    *           关键数据：表中内容的必要数据，无此数据代表数据不完整
    *           关键数据的来源：
    *               1.数据库的约束
    *                   不能为空的字段
    *               2.前端页面中必要数据
    *                   用小红点来显示
    *               3.接口文档：Yapi
    *                   会体现出必要的数据
    *   3.将dto转为po数据，并且赋值审核状态的默认值
    *       保存：未提交
    *   4.保存数据
    *       4.1 保存课程基础信息
    *           判断保存的结果
    *       4.2 保存课程营销信息
    *           判断保存的结果
    *   5.将数据库的最新数据转为dto并返回
    * */
    @Transactional
    public CourseBaseDTO createCourseBase(CourseBaseDTO dto) {

        // 2.判断关键数据
        verifyCourseMsg(dto);


        // 3.将dto转为po数据，并且赋值审核状态的默认值
        CourseBase courseBase = CourseBaseConvert.INSTANCE.dto2entity(dto);
        //     保存：未提交
        courseBase.setAuditStatus(CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode());


        // 4.保存数据
        //     4.1 保存课程基础信息
        //         判断保存的结果
        //   如果mp对数据保存成功后，会将保存成功在数据库中的id值返回给courseBase中
        boolean baseResult = this.save(courseBase);

        if (!baseResult) {
            throw new RuntimeException("保存课程基础信息失败");
        }


        //     4.2 保存课程营销信息
        //         判断保存的结果
        CourseMarket courseMarket = new CourseMarket();

        courseMarket.setCourseId(courseBase.getId());
        courseMarket.setCharge(dto.getCharge());


        // 判断课程是否收费：
        //     1.如果是免费，无需给price赋值

        if (CourseChargeEnum.CHARGE_YES.getCode().equals(dto.getCharge())) {
            //     2.如果是收费，price必须有值
            if (ObjectUtils.isEmpty(dto.getPrice())) {
                throw new RuntimeException("收费课程的价格不能为空");
            }

            courseMarket.setPrice(dto.getPrice().floatValue());
        }
        boolean marketResult = courseMarketService.save(courseMarket);

        if (!marketResult) {
            throw new RuntimeException("保存课程营销信息失败");
        }

        // courseMarket.setPrice(dto.getPrice());


        // 5.将数据库的最新数据转为dto并返回
        CourseBaseDTO resultDTO = CourseBaseConvert.INSTANCE.entity2dto(courseBase);

        resultDTO.setCharge(dto.getCharge());
        resultDTO.setPrice(dto.getPrice());


        return resultDTO;
    }

    @Override
    public CourseBaseDTO getById(Long courseBaseId, Long companyId) {
        //1.判断关键数据 courseBaseId companyId
        if (ObjectUtils.isEmpty(courseBaseId)||
            ObjectUtils.isEmpty(companyId)){
            throw new RuntimeException(CommonErrorCode.E_100101.getDesc());
        }
        CourseBase courseBase = getCourseBaseAndLogicVerify(courseBaseId, companyId);
        //3.将数据转为dto并返回
        CourseBaseDTO dto = CourseBaseConvert.INSTANCE.entity2dto(courseBase);

        LambdaQueryWrapper<CourseMarket> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseMarket::getCourseId,courseBaseId);

        CourseMarket market = courseMarketService.getOne(queryWrapper);
        dto.setCharge(market.getCharge());
        dto.setPrice(new BigDecimal(market.getPrice().toString()));

        return dto;

    }

    private CourseBase getCourseBaseAndLogicVerify(Long courseBaseId, Long companyId) {
        // 2.判断业务数据
        //     课程基础信息
        //         课程是否是同一家教学机构
        //         判断课程是否已删除
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseBase::getId, courseBaseId);
        queryWrapper.eq(CourseBase::getCompanyId, companyId);

        CourseBase courseBase = this.getOne(queryWrapper);
        if (ObjectUtils.isEmpty(courseBase)){
            throw new RuntimeException("课程基础信息不存在");
        }
        //判断课程是否已删除
        Integer status = courseBase.getStatus();
        if (CommonEnum.DELETE_FLAG.equals(status)){
            throw new RuntimeException("课程基础信息已删除");
        }
        return courseBase;
    }

    @Transactional
    public CourseBaseDTO modifyCourseBase(CourseBaseDTO dto) {
        //1.判断关键数据
        //    参考添加的判断
        verifyCourseMsg(dto);
        //判断课程id是否为空
        if (ObjectUtils.isEmpty(dto.getCourseBaseId())){
            throw new RuntimeException("修改客户id不能为空");
        }
        // 2.判断业务数据
        //     课程基础信息
        //         判断是否是同一家教学机构
        //         判断课程是否被删除
        //         判断课程的审核状态
        //             只有 未提交、审核未通过 才可以修改数据
        // 修改的数据必须要有Id值
        CourseBase courseBase = getCourseBaseAndLogicVerify(dto.getCourseBaseId(), dto.getCompanyId());
        //判断课程状态是否是未提交和审核未通过
        String auditStatus = courseBase.getAuditStatus();
        if (CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)
        ) {
            throw new RuntimeException("课程审核状态异常");
        }
        // 3.转换dto数据为po数据
        CourseBase po = CourseBaseConvert.INSTANCE.dto2entity(dto);
        // 4.修改数据
        //     课程基础信息
        // 如果修改的实体数据比较多，updateById（要修改的实体类对象）
        boolean updateById = this.updateById(po);
        if (!updateById){
            throw new RuntimeException("修改课程基础信息失败");
        }
        //     课程营销信息
        // 如果修改的实体数据比较少，LambdaUpdateWrapper
        // update course_market set charge = ? ,  price = ? where courseid =?
        LambdaUpdateWrapper<CourseMarket> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseMarket::getCharge,dto.getCharge());

        float price = 0f;

        if (CourseChargeEnum.CHARGE_YES.getCode().equals(dto.getCharge())){
            price = dto.getPrice().floatValue();
        }
        updateWrapper.set(CourseMarket::getPrice,price);
        updateWrapper.eq(CourseMarket::getCourseId,dto.getCourseBaseId());

        boolean marketResult = courseMarketService.update(updateWrapper);
        if (!marketResult){
            throw new RuntimeException("修改课程营销信息失败");
        }
        // 5.将最新数据返回给dto
        CourseBase base = this.getById(dto.getCourseBaseId());
        CourseBaseDTO courseBaseDTO = CourseBaseConvert.INSTANCE.entity2dto(base);

        courseBaseDTO.setCharge(dto.getCharge());
        courseBaseDTO.setPrice(dto.getPrice());
        return courseBaseDTO;
    }

    @Transactional
    public RestResponse deleteCourseBase(Long courseId, Long companyId) {
        //判断关键数据 courseId companyId
        if (ObjectUtils.isEmpty(courseId)){
            if (ObjectUtils.isEmpty(companyId)){
                throw new RuntimeException("课程基础信息id或者公司id不能为空");
            }
        }
        //抽取的方法判断 审核状态
        CourseBase courseBase = getCourseBaseAndLogicVerify(courseId, companyId);
        //判断课程状态是否是未提交和审核未通过
        String auditStatus = courseBase.getAuditStatus();
        if (CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)
        ) {
            throw new RuntimeException("课程审核状态异常");
        }
        //update course_base set status = 0 where id = ?
        LambdaUpdateWrapper<CourseBase> updateWrapper = Wrappers.lambdaUpdate(CourseBase.class);
        updateWrapper.set(CourseBase::getStatus,0);
        updateWrapper.eq(CourseBase::getId,courseId);
        boolean deleteResult = this.update(updateWrapper);
        if (!deleteResult){
            throw new RuntimeException("删除课程失败");
        }

        return new RestResponse(0,"success");
    }

    @Transactional
    public void commitCourseBase(Long courseId, Long companyId) {
        /*
        业务分析 :
            1.判断关键数据
                courseId companyId
            2.判断业务数据
                判断审核状态
                    只有 未提交 和  未通过 才能修改成已提交
            3.修改课程并判断返回结果
            4.判断状态


         */
        //     课程基础信息
        // companyId  name  mt st  grade teachmode  users  pic（后期来判断）
      if (ObjectUtils.isEmpty(companyId)||ObjectUtils.isEmpty(courseId)){
          ExceptionCast.cast(CommonErrorCode.E_100101);
      }
        //         判断是否是同一家教学机构
        //         判断课程是否被删除
        //         判断课程的审核状态
        // 修改的数据必须要有Id值
        CourseBase courseBase = getCourseBaseAndLogicVerify(courseId,companyId);
        //判断课程状态是否是未提交和审核未通过
        // 只有 未提交、审核未通过 才可以修改数据
        String auditStatus = courseBase.getAuditStatus();
        if (CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)
        ) {
            throw new RuntimeException("课程审核状态异常");
        }
        //修改课程状态
        //update course_base set audit_status = ? where id = ?
        LambdaUpdateWrapper<CourseBase> updateWrapper = Wrappers.lambdaUpdate(CourseBase.class);
        updateWrapper.set(CourseBase::getAuditStatus, CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode());
        updateWrapper.eq(CourseBase::getId,courseId);
        boolean updateResult = this.update(updateWrapper);

        //判断修改结果
        if (!updateResult){
            ExceptionCast.cast(ContentErrorCode.E_120019);
        }
    }

    @Override
    public void approveCourse(CourseBaseDTO dto) {
        /*
        业务判断
        1.判断关键数据
            courseId
            auditMind
            audtiStatus
        2.判断业务数据
        3.修改审核状态
            审核状态必须为已提交
            审核后
         */
        //1.判断关键数据
        if (ObjectUtils.isEmpty(dto.getCourseBaseId())){
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        if (StringUtil.isBlank(dto.getAuditMind())){
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        if (StringUtil.isBlank(dto.getAuditStatus())){
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        //判断课程基本信息
        CourseBase courseBase = this.getById(dto.getCourseBaseId());
        // 判断课程是否存在
        ExceptionCast.cast(ObjectUtils.isEmpty(courseBase),ContentErrorCode.E_120013);

        // 判断课程是否删除
        ExceptionCast.cast(CommonEnum.DELETE_FLAG.getCodeInt().equals(courseBase.getStatus()),
                ContentErrorCode.E_120019);
        //2.判断业务数据
        //被审核的课程的课程状态必须为已提交

        if (!CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(courseBase.getAuditStatus())){
            ExceptionCast.cast(ContentErrorCode.E_120015);
        }

        //审核的状态必须为 审核通过 或者 审核未通过
        if (!(CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(dto.getAuditStatus())||
                CourseAuditEnum.AUDIT_DISPAST_STATUS.getCode().equals(dto.getAuditStatus()))){
            ExceptionCast.cast(ContentErrorCode.E_120020);
        }
        //修改审核状态
//     修改CourseBase表
        //         audtiStatus
        //         auditMind
        //         auditNum
        //         changeDate
        LambdaUpdateWrapper<CourseBase> updateWrapper = Wrappers.lambdaUpdate(CourseBase.class);
        updateWrapper.set(CourseBase::getAuditStatus,dto.getAuditStatus());
        updateWrapper.set(CourseBase::getAuditMind,dto.getAuditMind());
        updateWrapper.set(CourseBase::getAuditNums,courseBase.getAuditNums()+1);
        updateWrapper.set(CourseBase::getChangeDate,courseBase.getChangeDate());
        boolean Result = this.update(updateWrapper);
        if (!Result){
            ExceptionCast.cast(ContentErrorCode.E_120021);
        }


        //将dto转为po
        CourseBaseConvert.INSTANCE.dto2entity(dto);
    }


    private void verifyCourseMsg(CourseBaseDTO dto) {
        //2.判断关键数据
        //     课程基础信息
        // companyId  name  mt st  grade teachmode  users  pic（后期来判断）

        if (ObjectUtils.isEmpty(dto.getCompanyId())) {
            // 业务异常：程序员在做业务判断时，数据有问题。
            // 异常：
            //    1.终止程序
            //    2.传递错误信息
            //    3.使用运行时异常来抛出
            //        运行时异常不需在编译期间处理
            throw new RuntimeException("公司id不能为空");
        }

        if (StringUtil.isBlank(dto.getName())) {
            ExceptionCast.cast(ContentErrorCode.E_120004);
        }

        if (StringUtil.isBlank(dto.getMt())) {
            ExceptionCast.cast(ContentErrorCode.E_120002);
        }

        if (StringUtil.isBlank(dto.getSt())) {
            ExceptionCast.cast(ContentErrorCode.E_120003);
        }

        if (StringUtil.isBlank(dto.getGrade())) {
            ExceptionCast.cast(ContentErrorCode.E_120007);
        }

        if (StringUtil.isBlank(dto.getTeachmode())) {
            ExceptionCast.cast(ContentErrorCode.E_120006);
        }

        if (StringUtil.isBlank(dto.getUsers())) {
            ExceptionCast.cast(ContentErrorCode.E_120018);
        }

        if (StringUtil.isBlank(dto.getCharge())) {
            ExceptionCast.cast(ContentErrorCode.E_120104);
        }
    }


}